package com.tools.cleanmaster.ui.view;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.os.SystemClock;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.AdapterView;

/**
 * Created by gonggaofeng on 15/12/16.
 *
 */
public class RippleView {

    private final static int TOUCH_TAP_TIME_OUT = 100;

    private static int WINDOW_WIDTH;
    private static long mLastLongClickTime;
    private int mLongClickZoomDuration;
    private int mZoomDuration;
    private int mRippleDisappearDuration;
    private final View mView;
    private float mRippleCenterX;
    private float mLongClickFrameRate;
    private float mCenterX;
    private float mRippleCenterY;
    private float mCircleRadius;
    private float mLongClickCircleRate;
    private float mRippleRadius;
    private float mRippleAlphaRatio;
    private float mRippleDisappearRate;
    private float mDefaultAlphaRatio;
    private final Paint mPaint;
    private boolean mHandleable;
    private boolean hasClicked;
    private int mViewRight;
    private int mViewBottom;
    private RectF mRectF;

    private float mRippleCornerRadius;
    private int mRippleBackground = Color.TRANSPARENT;
    private int mRippleColor = Color.TRANSPARENT;

    private boolean drawRipple = true;
    private boolean mDrawGuide = false;
    private int mDrawGuideDuration = 800;

    private Runnable mRippleDrawThread;

    public RippleView(View view) {
        view.setClickable(true);
        mView = view;
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
    }

    public static void onClick(RippleView rippleView) {
        rippleView.sendClickEvent();
    }

    private boolean hasTouched(ViewGroup viewGroup, float axisX, float axisY) {
        int childCount = viewGroup.getChildCount();
        if (childCount <= 0) {
            return false;
        }

        for (int i = 0; i < childCount; ++i) {
            View child = viewGroup.getChildAt(i);
            if (child.getVisibility() == View.VISIBLE) {
                if (child instanceof ViewGroup) {
                    if ((axisX >= child.getRight())
                            || (axisX <= child.getLeft())
                            || (axisY >= child.getBottom())
                            || (axisY <= child.getTop())
                            || (!(hasTouched((ViewGroup) child,
                            axisX - child.getLeft(),
                            axisY - child.getTop())))) {
                        continue;
                    }
                } else {
                    if ((child.isClickable()) && (axisX < child.getRight())
                            && (axisX > child.getLeft())
                            && (axisY < child.getBottom())
                            && (axisY > child.getTop())) {
                        return true;
                    }
                }
            }
        }
        return false;
    }

    public static View getView(RippleView rippleView) {
        return rippleView.mView;
    }

    private void refreshRatio() {
        if (mHandleable) {
            if (mRippleDisappearRate > 0F) {
                mRippleAlphaRatio = 0.1F;
                mRippleDisappearRate = (-mRippleDisappearRate);
                mDefaultAlphaRatio = 0F;
                mLongClickFrameRate = (mLongClickFrameRate
                        * mLongClickZoomDuration / mZoomDuration);
                mLongClickCircleRate = (mLongClickCircleRate
                        * mLongClickZoomDuration / mZoomDuration);
            }
        }

    }

    private void sendClickEvent() {
        try {
            View parentView = (View) mView.getParent();
            if (parentView instanceof AdapterView) {
                AdapterView adapterView = (AdapterView) parentView;
                int position = adapterView.getPositionForView(mView);
                AdapterView.OnItemClickListener onItemClickListener = adapterView
                        .getOnItemClickListener();
                if (onItemClickListener != null) {
                    onItemClickListener
                            .onItemClick(adapterView, mView, position,
                                    adapterView.getItemIdAtPosition(position));
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void setRippleCornerRadius(float radius) {
        mRippleCornerRadius = radius;
    }

    public void setRippleBackgroud(int color) {
        mRippleBackground = color;
    }

    public void setRippleColor(int color) {
        mRippleColor = color;
    }

    public final void draw(Canvas canvas) {
        if ((mHandleable) && (drawRipple)) {
            canvas.save();
            int scrollX = mView.getScrollX();
            int scrollY = mView.getScrollY();
            if ((scrollX != 0) || (scrollY != 0)) {
                canvas.translate(scrollX, scrollY);
            }

            mPaint.reset();
            mPaint.setAntiAlias(true);
            mPaint.setColor(mRippleBackground);

            if (mRippleCornerRadius == 0F) {
                mPaint.setAlpha((int) (255.0F * mRippleAlphaRatio));
                canvas.drawRect(0F, 0F, mViewRight, mViewBottom, mPaint);
            } else {
                canvas.drawRoundRect(mRectF, mRippleCornerRadius,
                        mRippleCornerRadius, mPaint);
            }

            mRippleAlphaRatio += mRippleDisappearRate;
            if (mRippleDisappearRate < 0F) {
                if (mRippleAlphaRatio < mDefaultAlphaRatio) {
                    mRippleAlphaRatio = mDefaultAlphaRatio;
                    mHandleable = false;
                    if (hasClicked) {
                        mView.post(new RippleTask(this));
                        hasClicked = false;
                    }
                }
            } else {
                if (mRippleAlphaRatio > mDefaultAlphaRatio) {
                    mRippleAlphaRatio = mDefaultAlphaRatio;
                }
            }

            if ((mRippleCornerRadius == 0F)) {

//                if (mDefaultAlphaRatio == 0.1F) {
//                    mPaint.setAlpha(25);
//                }
                mPaint.setColor(mRippleColor);

                canvas.drawCircle(mRippleCenterX, mRippleCenterY,
                        mCircleRadius, mPaint);
            } else {
                canvas.drawRoundRect(mRectF, mRippleCornerRadius,
                        mRippleCornerRadius, mPaint);
                int bgCount = canvas.saveLayer(mRectF, mPaint, Canvas.ALL_SAVE_FLAG);

                mPaint.setColor(Color.WHITE);
                canvas.drawRoundRect(mRectF, mRippleCornerRadius,
                        mRippleCornerRadius, mPaint);

                mPaint.setColor(mRippleColor);
                mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
                canvas.drawCircle(mRippleCenterX, mRippleCenterY,
                        mCircleRadius, mPaint);

                canvas.restoreToCount(bgCount);
            }

            mRippleCenterX += mLongClickFrameRate;
            if (mLongClickFrameRate < 0F) {
                if (mRippleCenterX < mCenterX) {
                    mRippleCenterX = mCenterX;
                }
            } else {
                if (mRippleCenterX > mCenterX) {
                    mRippleCenterX = mCenterX;
                }
            }

            mCircleRadius += mLongClickCircleRate;
            if (mCircleRadius > mRippleRadius) {
                mCircleRadius = mRippleRadius;
            }
            canvas.restore();
            mView.invalidate();
        }

//        if (mGuideAnim) {
//            drawGuideRipple(canvas);
//        }

    }

    public final void onTouchEvent(MotionEvent motionEvent) {
        if (drawRipple) {

            switch (motionEvent.getAction()) {
                case MotionEvent.ACTION_DOWN: {
                    onTouchDown(motionEvent);
                    break;
                }

                case MotionEvent.ACTION_MOVE: {
                    onTouchMove(motionEvent);
                    break;
                }

                case MotionEvent.ACTION_CANCEL: {
                    onTouchCancel();
                    break;
                }

                case MotionEvent.ACTION_UP: {
                    onTouchUp();
                    break;
                }

                default: {
                    mDrawGuide = false;
                    break;
                }

            }

        }
    }

    private void onTouchDown(MotionEvent event){
        if ((hasClicked) || (!(mView.isEnabled()))
                || ((mView instanceof ViewGroup) && (hasTouched((ViewGroup) mView, event.getX(), event.getY())))) {
            return;
        }

        mHandleable = true;
        mRippleCenterY = event.getY();
        if (WINDOW_WIDTH == 0) {
            WINDOW_WIDTH = ((WindowManager) mView.getContext()
                    .getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay()
                    .getWidth();
        }

        mViewRight = mView.getWidth();
        mViewBottom = mView.getHeight();
        if (mRectF == null) {
            mRectF = new RectF(0, 0, mViewRight, mViewBottom);
        }

        if(!mDrawGuide) {
            mLongClickZoomDuration = (int) (2000.0F * mViewRight / WINDOW_WIDTH);
            if(mLongClickZoomDuration < 1000) {
                mLongClickZoomDuration = 1000;
            }
        } else {
            mLongClickZoomDuration = mDrawGuideDuration;
        }

        mZoomDuration = 300;
        mRippleDisappearDuration = 400;
        mRippleCenterX = event.getX();
        mCenterX = (mViewRight >> 1);
        mLongClickFrameRate = (20.0F * (mCenterX - mRippleCenterX) / mLongClickZoomDuration);
        mCircleRadius = 0F;
        int bottom = mViewBottom;
        if (mRippleCenterY >= bottom >> 1) {
            mRippleRadius = (float) Math.sqrt(Math.pow(mViewRight >> 1,
                    2.0D) + Math.pow(mRippleCenterY, 2.0D));
        } else {
            mRippleRadius = (float) Math.sqrt(Math.pow(mViewRight >> 1,
                    2.0D) + Math.pow(bottom - mRippleCenterY, 2.0D));
        }

        mLongClickCircleRate = (20.0F * (mRippleRadius - mCircleRadius) / mLongClickZoomDuration);
        mRippleAlphaRatio = 0F;
        mDefaultAlphaRatio = 0.1F;
        mRippleDisappearRate = (2F / mRippleDisappearDuration);
        mRippleDrawThread = new RippleDrawTask();
        mView.postDelayed(mRippleDrawThread,TOUCH_TAP_TIME_OUT);
    }

    private void onTouchMove(MotionEvent event){
        float axisX = event.getX();
        float axisY = event.getY();
        if ((axisX < 0F) || (axisX > mViewRight) || (axisY < 0F)
                || (axisY > mViewBottom)) {
            refreshRatio();
            mView.removeCallbacks(mRippleDrawThread);
            mRippleDrawThread = null;
            mHandleable = false;
            hasClicked = false;
        }
    }

    private void onTouchCancel(){
        refreshRatio();
        mView.removeCallbacks(mRippleDrawThread);
        mRippleDrawThread = null;
        mHandleable = false;
        hasClicked = false;
    }

    private void onTouchUp(){
        refreshRatio();
    }


    public final boolean isHandleable() {
        return mHandleable;
    }

    public final void onLongClick() {
        long now = System.currentTimeMillis();
        if (Math.abs(now - mLastLongClickTime) > 200L) {
            mLastLongClickTime = now;
            hasClicked = true;
        }
    }

    public final void disableRipple() {
        drawRipple = false;
    }

    public final void enableRipple() {
        drawRipple = true;
    }

    public final void refreshValues() {
        refreshRatio();
    }

    public final class RippleTask implements Runnable {

        private final RippleView mRippleView;

        public RippleTask(RippleView rippleView) {
            mRippleView = rippleView;
        }

        @Override
        public final void run() {
            RippleView.onClick(mRippleView);
            RippleView.getView(mRippleView).performClick();
        }

    }

    public void drawGuideRipple() {
        mDrawGuide = true;
        int times = 3;
        final float x = mView.getWidth() / 2.0f;
        final float y = mView.getHeight() / 2.0f;

        for (int i = 0; i < times; i++) {
            mView.postDelayed(new Runnable() {
                @Override
                public void run() {
                    onTouchEvent(MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(),
                            MotionEvent.ACTION_DOWN, x, y, 0));
                }
            }, mDrawGuideDuration * i);
        }

        mView.postDelayed(new Runnable() {
            @Override
            public void run() {
                onTouchEvent(MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(),
                        MotionEvent.ACTION_CANCEL, x, y, 0));
                mDrawGuide = false;
            }
        }, mDrawGuideDuration * (times + 1));

    }

    class RippleDrawTask implements Runnable {

        @Override
        public void run() {
            mView.invalidate();
        }

    }

    public void resetSize(int width,int height){
        this.mViewRight = width;
        this.mViewBottom = height;
        if (mRectF == null) {
            mRectF = new RectF(0, 0, mViewRight, mViewBottom);
        } else {
            mRectF.set(0,0,mViewRight,mViewBottom);
        }
    }

}
